 /*******************************************************************************
  * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.internal;

 import java.util.HashMap ;
 import java.util.Iterator ;
 import java.util.List ;
 import java.util.Map ;

 import org.eclipse.core.runtime.IExtension;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.MultiStatus;
 import org.eclipse.core.runtime.SafeRunner;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
 import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
 import org.eclipse.jface.util.SafeRunnable;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.ui.IMemento;
 import org.eclipse.ui.IViewPart;
 import org.eclipse.ui.IViewReference;
 import org.eclipse.ui.IWorkbenchPart3;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.views.IViewDescriptor;
 import org.eclipse.ui.views.IViewRegistry;

 /**
  * The ViewFactory is used to control the creation and disposal of views.
  * It implements a reference counting strategy so that one view can be shared
  * by more than one client.
  */
 /*package*/class ViewFactory implements IExtensionChangeHandler {

     private ReferenceCounter counter;

     private HashMap mementoTable = new HashMap ();

     WorkbenchPage page;

     IViewRegistry viewReg;

     /**
      * Separates a view's primary id from its secondary id in view key strings.
      */
     static final String ID_SEP = ":"; //$NON-NLS-1$

     /**
      * Returns a string representing a view with the given id and (optional) secondary id,
      * suitable for use as a key in a map.
      *
      * @param id primary id of the view
      * @param secondaryId secondary id of the view or <code>null</code>
      * @return the key
      */
     static String getKey(String id, String secondaryId) {
         return secondaryId == null ? id : id + ID_SEP + secondaryId;
     }

     /**
      * Returns a string representing the given view reference, suitable for use as a key in a map.
      *
      * @param viewRef the view reference
      * @return the key
      */
     static String getKey(IViewReference viewRef) {
         return getKey(viewRef.getId(), viewRef.getSecondaryId());
     }

     /**
      * Extracts ths primary id portion of a compound id.
      * @param compoundId a compound id of the form: primaryId [':' secondaryId]
      * @return the primary id
      */
     static String extractPrimaryId(String compoundId) {
         int i = compoundId.lastIndexOf(ID_SEP);
         if (i == -1) {
             return compoundId;
         }
         return compoundId.substring(0, i);
     }

     /**
      * Extracts ths secondary id portion of a compound id.
      * @param compoundId a compound id of the form: primaryId [':' secondaryId]
      * @return the secondary id, or <code>null</code> if none
      */
     static String extractSecondaryId(String compoundId) {
         int i = compoundId.lastIndexOf(ID_SEP);
         if (i == -1) {
             return null;
         }
         return compoundId.substring(i + 1);
     }

     /**
      * Returns whether the given view id contains a wildcard. Wildcards cannot
      * be used in regular view ids, only placeholders.
      *
      * @param viewId the view id
      * @return <code>true</code> if the given view id contains a wildcard,
      * <code>false</code> otherwise
      *
      * @since 3.1
      */
     static boolean hasWildcard(String viewId) {
         return viewId.indexOf(PartPlaceholder.WILD_CARD) >= 0;
     }
     
     /**
      * Constructs a new view factory.
      */
     public ViewFactory(WorkbenchPage page, IViewRegistry reg) {
         super();
         this.page = page;
         this.viewReg = reg;
         counter = new ReferenceCounter();
         page.getExtensionTracker().registerHandler(this, null);
     }
     
     /**
      * Creates an instance of a view defined by id.
      *
      * This factory implements reference counting. The first call to this
      * method will return a new view. Subsequent calls will return the
      * first view with an additional reference count. The view is
      * disposed when releaseView is called an equal number of times
      * to getView.
      */
     public IViewReference createView(final String id) throws PartInitException {
         return createView(id, null);
     }

     /**
      * Creates an instance of a view defined by id and secondary id.
      *
      * This factory implements reference counting. The first call to this
      * method will return a new view. Subsequent calls will return the
      * first view with an additional reference count. The view is
      * disposed when releaseView is called an equal number of times
      * to createView.
      */
     public IViewReference createView(String id, String secondaryId)
             throws PartInitException {
         IViewDescriptor desc = viewReg.find(id);
         // ensure that the view id is valid
 if (desc == null) {
             throw new PartInitException(NLS.bind(WorkbenchMessages.ViewFactory_couldNotCreate, id ));
         }
         // ensure that multiple instances are allowed if a secondary id is given
 if (secondaryId != null) {
             if (!desc.getAllowMultiple()) {
                 throw new PartInitException(NLS.bind(WorkbenchMessages.ViewFactory_noMultiple, id));
             }
         }
         String key = getKey(id, secondaryId);
         IViewReference ref = (IViewReference) counter.get(key);
         if (ref == null) {
             IMemento memento = (IMemento) mementoTable.get(key);
             ref = new ViewReference(this, id, secondaryId, memento);
             mementoTable.remove(key);
             counter.put(key, ref);
             getWorkbenchPage().partAdded((ViewReference)ref);
         } else {
             counter.addRef(key);
         }
         return ref;
     }
     
     /**
      * Returns the set of views being managed by this factory
      *
      * @return the set of views being managed by this factory
      */
     public IViewReference[] getViewReferences() {
         List values = counter.values();
         
         return (IViewReference[]) values.toArray(new IViewReference[values.size()]);
     }

     /**
      * Returns the view with the given id, or <code>null</code> if not found.
      */
     public IViewReference getView(String id) {
         return getView(id, null);
     }

     /**
      * Returns the view with the given id and secondary id, or <code>null</code> if not found.
      */
     public IViewReference getView(String id, String secondaryId) {
         String key = getKey(id, secondaryId);
         return (IViewReference) counter.get(key);
     }

     /**
      * @return the <code>IViewRegistry</code> used by this factory.
      * @since 3.0
      */
     public IViewRegistry getViewRegistry() {
         return viewReg;
     }

     /**
      * Returns a list of views which are open.
      */
     public IViewReference[] getViews() {
         List list = counter.values();
         IViewReference[] array = new IViewReference[list.size()];
         list.toArray(array);
         return array;
     }

     /**
      * @return the <code>WorkbenchPage</code> used by this factory.
      * @since 3.0
      */
     public WorkbenchPage getWorkbenchPage() {
         return page;
     }

     /**
      *
      * @param viewRef
      * @return the current reference count for the given view
      */
     public int getReferenceCount(IViewReference viewRef) {
         String key = getKey(viewRef);
         IViewReference ref = (IViewReference) counter.get(key);
         return ref==null ? 0 : counter.getRef(key);
     }
     
     /**
      * Releases an instance of a view.
      *
      * This factory does reference counting. For more info see
      * getView.
      */
     public void releaseView(IViewReference viewRef) {
         String key = getKey(viewRef);
         IViewReference ref = (IViewReference) counter.get(key);
         if (ref == null) {
             return;
         }
         int count = counter.removeRef(key);
         if (count <= 0) {
             getWorkbenchPage().partRemoved((ViewReference)ref);
         }
     }

     /**
      * Restore view states.
      *
      * @param memento the <code>IMemento</code> to restore from.
      * @return <code>IStatus</code>
      */
     public IStatus restoreState(IMemento memento) {
         IMemento mem[] = memento.getChildren(IWorkbenchConstants.TAG_VIEW);
         for (int i = 0; i < mem.length; i++) {
             //for dynamic UI - add the next line to replace subsequent code that is commented out
 restoreViewState(mem[i]);
         }
         return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, 0, "", null); //$NON-NLS-1$
 }

     /**
      * Save view states.
      *
      * @param memento the <code>IMemento</code> to save to.
      * @return <code>IStatus</code>
      */
     public IStatus saveState(IMemento memento) {
         final MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID,
                 IStatus.OK, WorkbenchMessages.ViewFactory_problemsSavingViews, null);

         final IViewReference refs[] = getViews();
         for (int i = 0; i < refs.length; i++) {
             //for dynamic UI - add the following line to replace subsequent code which is commented out
 saveViewState(memento, refs[i], result);
         }
         return result;
     }

     // for dynamic UI
 public IMemento saveViewState(IMemento memento, IViewReference ref,
             MultiStatus res) {
         final MultiStatus result = res;
         final IMemento viewMemento = memento
                 .createChild(IWorkbenchConstants.TAG_VIEW);
         viewMemento.putString(IWorkbenchConstants.TAG_ID, ViewFactory
                 .getKey(ref));
         if (ref instanceof ViewReference) {
             viewMemento.putString(IWorkbenchConstants.TAG_PART_NAME,
                     ((ViewReference) ref).getPartName());
         }
         final IViewReference viewRef = ref;
         final IViewPart view = (IViewPart) ref.getPart(false);
         if (view != null) {
             SafeRunner.run(new SafeRunnable() {
                 public void run() {
                     if (view instanceof IWorkbenchPart3) {
                         Map properties = ((IWorkbenchPart3) view)
                                 .getPartProperties();
                         if (!properties.isEmpty()) {
                             IMemento propBag = viewMemento
                                     .createChild(IWorkbenchConstants.TAG_PROPERTIES);
                             Iterator i = properties.entrySet().iterator();
                             while (i.hasNext()) {
                                 Map.Entry entry = (Map.Entry ) i.next();
                                 IMemento p = propBag.createChild(
                                         IWorkbenchConstants.TAG_PROPERTY,
                                         (String ) entry.getKey());
                                 p.putTextData((String ) entry.getValue());
                             }
                         }
                     }
                     view.saveState(viewMemento
                             .createChild(IWorkbenchConstants.TAG_VIEW_STATE));
                 }

                 public void handleException(Throwable e) {
                     result
                             .add(new Status(
                                     IStatus.ERROR,
                                     PlatformUI.PLUGIN_ID,
                                     0,
                                     NLS.bind(WorkbenchMessages.ViewFactory_couldNotSave, viewRef.getTitle() ),
                                     e));
                 }
             });
         } else {
             IMemento mem = null;
             IMemento props = null;
             
             // if we've created the reference once, any previous workbench
 // state memento is there. After once, there is no previous
 // session state, so it should be null.
 if (ref instanceof ViewReference) {
                 mem = ((ViewReference) ref).getMemento();
                 if (mem!=null) {
                     props = mem.getChild(IWorkbenchConstants.TAG_PROPERTIES);
                 }
                 if (mem!=null) {
                     mem = mem.getChild(IWorkbenchConstants.TAG_VIEW_STATE);
                 }
             }
             if (props != null) {
                 viewMemento.createChild(IWorkbenchConstants.TAG_PROPERTIES)
                         .putMemento(props);
             }
             if (mem != null) {
                 IMemento child = viewMemento
                         .createChild(IWorkbenchConstants.TAG_VIEW_STATE);
                 child.putMemento(mem);
             }
         }
         return viewMemento;
     }

     // for dynamic UI
 public void restoreViewState(IMemento memento) {
         String compoundId = memento.getString(IWorkbenchConstants.TAG_ID);
         mementoTable.put(compoundId, memento);
     }

     IMemento getViewState(String key) {
         IMemento memento = (IMemento) mementoTable.get(key);

         if (memento == null) {
             return null;
         }

         return memento.getChild(IWorkbenchConstants.TAG_VIEW_STATE);
     }

     /* (non-Javadoc)
      * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#removeExtension(org.eclipse.core.runtime.IExtension, java.lang.Object[])
      */
     public void removeExtension(IExtension source, Object [] objects) {
         for (int i = 0; i < objects.length; i++) {
             if (objects[i] instanceof IViewPart) {
                 IViewPart part = (IViewPart) objects[i];
                 // String primaryViewId = part.getViewSite().getId();
 // String secondaryViewId = part.getViewSite().getSecondaryId();
 // IViewReference viewRef = page.findViewReference(
 // primaryViewId, secondaryViewId);
 // IPerspectiveDescriptor[] descs =
 // page.getOpenedPerspectives();
 // Perspective active = page.getActivePerspective();
 // for (int i = 0; i < descs.length; i++) {
 // Perspective nextPerspective = page.findPerspective(descs[i]);
 //
 // if (nextPerspective == null || active == nextPerspective)
 // continue;
 //
 // page.hideView(nextPerspective, viewRef);
 // }
 page.hideView(part);
             }

         }
     }
     
     /* (non-Javadoc)
      * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#addExtension(org.eclipse.core.runtime.dynamicHelpers.IExtensionTracker, org.eclipse.core.runtime.IExtension)
      */
     public void addExtension(IExtensionTracker tracker,IExtension extension) {
         //Do nothing
 }

 }


